home *** CD-ROM | disk | FTP | other *** search
- (* <<<Connect232.Pas>>> *)
- MODULE Connect232 ;
-
- (*)
- * A communications routine via the RS232 line to another host.
- * Parameters are:
- *
- * EscChar The "escape" character, when this character is read
- * from the keyboard return to caller.
- * HalfDuplex The state of the host's connection, if HalfDuplex is
- * true echo the keyboard characters locally.
- * TabletOk If true, the yellow button on the puck causes an
- * exit too.
- 5-Oct-83. Change cursor shape and allow ANY puck button
- to cause an exit.
- * RETURN: ConCharExit if <EscChar> caused exit,
- * ConButtonExit for puck button.
- (*)
-
- EXPORTS (*-------------*)
-
- IMPORTS IO_Unit FROM IO_Unit;
- IMPORTS IOErrors FROM IOErrors;
-
- TYPE
- (* What caused "Connect" to exit *)
- ConExitFlag = (ConCharExit, ConButtonExit) ;
-
-
- FUNCTION Connect( EscChar: Char; HalfDuplex, TabletOk: Boolean ) : ConExitFlag;
-
-
- PRIVATE (*---------------*)
-
- IMPORTS Screen FROM Screen ;
- IMPORTS System FROM System ;
- IMPORTS IO_Others FROM IO_Others;
-
- FUNCTION Connect( EscChar: Char; HalfDuplex, TabletOk: Boolean ) : ConExitFlag;
- CONST
- NUL = Chr(#000) ;
- BS = Chr(#010) ;
- TAB = Chr(#011) ;
- LF = Chr(#012) ;
- CR = Chr(#015) ;
- CtrlQ = Chr(#021) ;
- CtrlS = Chr(#023) ;
- VAR
- hpos: Integer ; (* current position in the line (for tabs) *)
- oldX, oldY: Integer ; (* Old cursor offsets *)
- quit: Boolean ; (* loop control *)
- LineChr, KeyChr: Char; (* current RS232 and keyboard characters *)
- OldCurs, NewCurs: CurPatPtr ; (* Old and New cursors (if TabletOk) *)
- return: ConExitFlag ; (* the exit flag *)
-
- PROCEDURE WriteChr( c: Char ) ;
- BEGIN
- SPutChr( c ) ;
- Hpos := Hpos + 1
- END ;
-
- HANDLER CtlC ;
- BEGIN
- END ;
-
- BEGIN (*-Connect-*)
-
- (* Allocate cursor space *)
- New( 0, 4, NewCurs) ;
- New( 0, 4, OldCurs) ;
-
- (* Clear the cursor area *)
- RasterOp(RXor, 64, 64, 0, 0, 4, RECAST(NewCurs, RasterPtr),
- 0, 0, 4, RECAST(NewCurs, RasterPtr) ) ;
-
- (* Cursor values from file: Connect3.Cursor *)
- NewCurs^[ 0,0] := #40 ;
- NewCurs^[ 1,0] := #120 ;
- NewCurs^[ 1,1] := #1642 ;
- NewCurs^[ 1,2] := #167000 ;
- NewCurs^[ 2,0] := #210 ;
- NewCurs^[ 2,1] := #1024 ;
- NewCurs^[ 2,2] := #42000 ;
- NewCurs^[ 3,0] := #404 ;
- NewCurs^[ 3,1] := #1610 ;
- NewCurs^[ 3,2] := #42000 ;
- NewCurs^[ 4,0] := #1002 ;
- NewCurs^[ 4,1] := #1024 ;
- NewCurs^[ 4,2] := #42000 ;
- NewCurs^[ 5,0] := #404 ;
- NewCurs^[ 5,1] := #1642 ;
- NewCurs^[ 5,2] := #162000 ;
- NewCurs^[ 6,0] := #2211 ;
- NewCurs^[ 7,0] := #5122 ;
- NewCurs^[ 7,1] := #100000 ;
- NewCurs^[ 8,0] := #10444 ;
- NewCurs^[ 8,1] := #40000 ;
- NewCurs^[ 9,0] := #20210 ;
- NewCurs^[ 9,1] := #20000 ;
- NewCurs^[10,0] := #40120 ;
- NewCurs^[10,1] := #10000 ;
- NewCurs^[11,0] := #20210 ;
- NewCurs^[11,1] := #20000 ;
- NewCurs^[12,0] := #10444 ;
- NewCurs^[12,1] := #40000 ;
- NewCurs^[13,0] := #5122 ;
- NewCurs^[13,1] := #100000 ;
- NewCurs^[14,0] := #2211 ;
- NewCurs^[15,0] := #404 ;
- NewCurs^[16,0] := #1002 ;
- NewCurs^[17,0] := #404 ;
- NewCurs^[18,0] := #210 ;
- NewCurs^[19,0] := #120 ;
- NewCurs^[20,0] := #40 ;
-
-
- (* Debug :- %)
- Writeln('TabletOk = ', TabletOk) ;
- (% Debug *)
-
-
- SCurOn ; (* ? *)
-
-
- (* Set up our cursor, or turn the cursor off if we can't use a cursor *)
- IF TabletOk THEN
- BEGIN
- IOReadCursPicture( OldCurs, oldX, oldY ) ;
- IOLoadCursor( NewCurs, 0, 0) ;
- IOSetModeTablet( relTablet ) ;
- IOCursorMode( TrackCursor )
- END
- ELSE
- IOCursorMode( OffCursor ) ; (* Turn it off *)
-
- return := ConCharExit ; (* Assume the exit by escape char *)
- quit := False ;
- WHILE NOT quit DO
- BEGIN
- (*---------- RS232 Input ----------*)
- IF (IOCRead(RS232In, LineChr)=IOEIOC) THEN
- BEGIN
- LineChr := Chr( Land( Ord(LineChr), #177) ) ;
- IF (LineChr = TAB) THEN
- BEGIN
- WriteChr( ' ' ) ;
- WHILE (Hpos MOD 8) <> 0 DO WriteChr( ' ' )
- END
- ELSE
- IF (LineChr = BS) THEN
- BEGIN
- IF Hpos > 0 THEN
- BEGIN (* Delete the character *)
- SBackSpace( ' ' );
- SPutChr( ' ' ) ;
- SBackSpace( ' ' ) ;
- Hpos := Hpos - 1
- END
- END
- ELSE
- IF (LineChr IN [NUL, CtrlS, CtrlQ]) THEN (* NOTHING *)
- ELSE
- WriteChr( LineChr ) ; (* write it *)
-
- IF (LineChr IN [CR, LF]) THEN Hpos := 0 ; (* a new line *)
- END ; (* RS232 input *)
-
- (*---------- Keyboard Input ----------*)
- IF (IOCRead(TransKey, KeyChr)=IOEIOC) THEN
- BEGIN
- IF (KeyChr = EscChar) THEN
- BEGIN
- quit := True
- END
- ELSE
- BEGIN
- IF IOCWrite(RS232Out, KeyChr)<>IOEIOC THEN
- KeyChr := Chr(#277) ;
- IF HalfDuplex THEN WriteChr( KeyChr )
- END
- END ; (* Keyboard input *)
-
- (*---------- Tablet Input ----------*)
- IF TabletOk AND TabSwitch THEN
- BEGIN
- return := ConButtonExit ;
- quit := True
- END
-
- END ; (* while *)
-
- (* Restore cursor *)
- IF TabletOk THEN IOLoadCursor( OldCurs, oldX, oldY )
- ELSE IOCursorMode( TrackCursor ) ; (* I assume it was originally on *)
- Dispose( NewCurs ) ;
-
- Connect := return
- END . (*-Connect-*)
-
- (* <<<Kermit.Pas>>> *)
- PROGRAM Kermit(Input,Output);
- (*)
- * 29-Nov-83 Allow eight bit file transfer with SET EIGHT-BIT ON/OFF
- * add global flag and extra SET command [pgt001]
- * For byte value 0..255 the end of (data) string value is now -1,
- * and end of file value -2.
- * 1-Dec-83 Place all globals into module KermitGlobals.
- (*)
-
-
-
- IMPORTS Stdio FROM Stdio ;
- IMPORTS KermitGlobals FROM KermitGlobals ; (**********)
- IMPORTS KermitUtils FROM KermitUtils ;
- IMPORTS KermitParms FROM KermitParms ;
- IMPORTS KermitHelp FROM KermitHelp ;
- IMPORTS KermitError FROM KermitError ;
- IMPORTS KermitSend FROM KermitSend ;
- IMPORTS KermitRecv FROM KermitRecv ;
-
- IMPORTS Connect232 FROM Connect232 ;
- IMPORTS PMatch FROM PMatch ;
- IMPORTS PopCmdParse FROM PopCmdParse ;
- IMPORTS Perq_String FROM Perq_String ;
- IMPORTS Screen FROM Screen ;
- IMPORTS IO_Unit FROM IO_Unit ;
- IMPORTS IOErrors FROM IOErrors;
- IMPORTS IO_Others FROM IO_Others;
- IMPORTS System FROM System;
- IMPORTS Sleep FROM Sleep;
-
-
-
-
-
-
- (* Handle ^C's from the console -pt*)
- HANDLER CtlC ;
- BEGIN (*-CtlC-*)
- IOKeyClear ; (* Remove ^C from input stream *)
- CtrlCPending := False ; (* Clear to prevent next ^C from aborting job *)
- FromConsole := AbortNow (* Set our flag *)
- END ; (*-CtlC-*)
-
-
- HANDLER HelpKey(VAR str: Sys9s) ;
- (* Make the HELP key generate the correct command (i.e. not a switch) -pt*)
- BEGIN (*-HelpKey-*)
- str := 'HELP ' ;
- str[5] := Chr( CR )
- END ; (*-HelpKey-*)
-
- PROCEDURE OverHd( p,f: Stats;
- VAR o:Integer);
-
- (* Calculate OverHead as % *)
- (* OverHead := (p-f)*100/f *)
-
- BEGIN
- IF (f = 0.0) THEN o := 0
- ELSE o := Round( (p-f)*100/f )
- END;
-
- PROCEDURE CalRat(f: Stats;
- t:Integer;
- VAR r:Integer);
-
- (* Calculate Effective Baud Rate *)
- (* Rate = f*10/t *)
-
- BEGIN
- IF (t = 0) THEN r := 0
- ELSE r := Round( f*10/t )
- END;
-
-
- PROCEDURE Statistics ;
- VAR
- overhead, effrate : Integer;
- BEGIN (*-Statistics-*)
- (* print info on number of packets etc *)
- (* All output here was originally to STDERR -pt*)
- Writeln ;
- Writeln('Packets sent: ',NumSendPacks:1);
- Writeln('Packets received: ',NumRecvPacks:1);
-
- (* Calculate overhead *)
- OverHd(ChInPack,ChInFile,overhead);
- IF (Overhead <> 0) THEN
- BEGIN
- Writeln('Overhead (%): ' ,overhead:1);
- END;
- IF (RunTime <> 0) THEN
- BEGIN (* calculate effective rate *)
- CalRat(ChInFile,RunTime,effrate);
- Writeln('Effective Rate: ',effrate:1);
- END;
-
- (* Transmit stats *)
- Inverse( TRUE ) ;
- Writeln(' Send :-') ;
- Inverse( FALSE ) ;
- Writeln('Number of ACK: ',NumACKrecv:1);
- Writeln('Number of NAK: ',NumNAKrecv:1);
- Writeln('Number of BAD: ',NumBADrecv:1);
-
- (* Transmit stats *)
- Inverse( TRUE ) ;
- Writeln(' Receive :-') ;
- Inverse( FALSE ) ;
- Writeln('Number of ACK: ',NumACK:1);
- Writeln('Number of NAK: ',NumNAK:1);
- Writeln
- END ; (*-Statistics-*)
-
- PROCEDURE FinishUp; (* do any End of Program clean up *)
- BEGIN
- Sclose(DiskFile);
- SYSfinish; (* do System dependent *)
- END;
-
-
-
- PROCEDURE DoConnect ;
- (* Connect to the other host -pt*)
- VAR
- whyExit: ConExitFlag ; (* Why "connect" exited *)
- ch: Char ; (* the character after the "escape" char *)
- BEGIN (*-DoConnect-*)
- Writeln('[Connecting to host. Type Control-', EscPrint,
- ' C or any button on the puck]') ;
- REPEAT
- whyExit := Connect( EscapeChar, HalfDuplex, TRUE) ;
- (* Get the command *)
- IF (whyExit = ConButtonExit) THEN (* the button was pressed *)
- BEGIN
- Nap( 10 ) ;
- ch := 'C' (* Close the connection *)
- END
- ELSE
- WHILE (IOCRead(TransKey, ch) <> IOEIOC) DO ;
-
- IF (ch = EscapeChar) THEN XmtChar( EscapeChar )
- ELSE
- IF (ch = '?') THEN
- BEGIN
- Writeln ;
- Writeln('When CONNECT''ed to another host, type Control-', EscPrint) ;
- Writeln('followed by :-') ;
- Writeln(' C to close the connection') ;
- Writeln(' ^', EscPrint, ' to send that character') ;
- Writeln(' ? for this information') ;
- Writeln('[Back to host]')
- END (* help *)
-
- UNTIL (Uppercase(ch) = 'C') ;
- Writeln ;
- Writeln('[Connection closed. Returning to PERQ]')
- END ; (*-DoConnect-*)
-
- BEGIN
- StdIOInit;
- SYSinit; (* system dependent *)
- done:=False;
-
- Writeln ;
- REPEAT
-
- KermitInit; (* initialize *)
-
- WHILE NOT (RunType IN [transmit, receive, setparm]) AND (NOT done)
- DO
- BEGIN
- CmdIndex := GetCmdLine(NullIdleProc, 'Kermit-PQ',
- CmdLine, CmdSpelling,
- Inf, RECAST(MainMenu, pNameDesc),
- firstPress, OK_to_pop) ;
- ConvUpper( CmdSpelling ) ; (* Make it upper case *)
- (* see what the command was *)
- CASE CmdIndex OF
- 1: DoConnect ; (* CONNECT *)
- 2: done := True ; (* EXIT *)
- 3: DoHelp ; (* HELP *)
- 4: done := True ; (* QUIT *)
- 5: RunType := Receive ; (* RECEIVE *)
- 6: RunType := Transmit; (* SEND *)
- 7: RunType := SetParm ; (* SET *)
- 8: DoShow ; (* SHOW *)
- 9: Statistics ; (* STATISTICS *)
-
- 10: Writeln('%Not a KERMIT command: ', CmdSpelling) ;
- 11: Writeln('%Ambiguous command: ', CmdSpelling) ;
- 12: (* empty line *) ;
- 13: Writeln('%KERMIT does not take switches, type HELP.');
- 14: Writeln('?Illegal character after command') ; (* ?? *)
- OTHERWISE: Writeln('?Unknown command: ', CmdSpelling)
- END (* case *)
- END;
-
- CASE RunType OF
- Receive:
- BEGIN (* filename is optional here *)
- (* Remove blanks from the cmd line *)
- IF (CmdLine <> '') THEN RemDelimiters( CmdLine, ' ', dumStr) ;
- IF GetArgument(aline) THEN
- BEGIN
- IF Exists(aline) AND FileWarning THEN
- BEGIN
- ErrorMsg('Overwriting: ');
- ErrorStr(aline);
- END;
-
- IF EightBitFile THEN (* [pgt001] *)
- DiskFile := Sopen(aline,StdIO8Write)
- ELSE
- DiskFile := Sopen(aline,StdIOWrite);
-
- IF (DiskFile <= StdIOError) THEN
- ErrorPack('Cannot Open File');
- END;
- RecvSwitch;
- END;
-
- Transmit:
- BEGIN (* New version -pt*)
- (* must give file name, so ask if one was not given -pt*)
- IF (CmdLine = '') THEN
- BEGIN
- Write('File to transmit ', PromptChar) ;
- Readln( CmdLine ) (* get the response *)
- END ;
-
- (* What shall we do with the line ? *)
- (* First remove blanks *)
- RemDelimiters( CmdLine, ' ', dumStr) ;
- IF (CmdLine = '') THEN (* another empty line, do nothing *)
- ELSE
- IF IsPattern(CmdLine) THEN
- Writeln('%SEND does not take wild file names')
- ELSE
- SendSwitch (* SendFile checks parameters - file exists *)
-
- END;
- Invalid: (* nothing *);
- SetParm: SetParameters ;
- END;
- (* case *)
-
- UNTIL done;
-
- FinishUp; (* End of Program *)
-
- ScreenReset (* Clear up screen data *)
- END.
-
- (* <<<KermitError.Pas>>> *)
- MODULE KermitError ;
-
-
-
- EXPORTS
-
- IMPORTS KermitGlobals FROM KermitGlobals ;
-
-
- PROCEDURE ErrorMsg(msg:MsgString ) ;
- PROCEDURE ErrorInt( msg:MsgString; n: Integer ) ;
- PROCEDURE ErrorStr( str: istring ) ;
- PROCEDURE DebugPacket(mes : MsgString;
- VAR p : Ppack);
- PROCEDURE Verbose(c:MsgString);
-
-
- PRIVATE
-
- IMPORTS Screen FROM Screen ;
-
-
- PROCEDURE ErrorMsg(msg:MsgString ) ;
- (* output literal preceeded by NEWLINE *)
- (* to the PERQ error window -pt*)
- BEGIN (*-ErrorMsg-*)
- ChangeWindow( ErrorWindow ) ;
- Writeln ;
- Write( msg ) ;
- ChangeWindow( KermitWindow )
- END; (*-ErrorMsg-*)
-
- PROCEDURE ErrorInt( msg:MsgString; n: Integer ) ;
- (* Output a number preceeded by a message *)
- (* to the PERQ error window -pt*)
- BEGIN (*-ErrorInt-*)
- ChangeWindow( ErrorWindow ) ;
- Writeln ;
- Write( msg, n:1 ) ;
- ChangeWindow( KermitWindow )
- END; (*-ErrorInt-*)
-
- PROCEDURE ErrorStr( str: istring ) ;
- (* Output a "istring" to the error window *)
- VAR i: Integer ;
- BEGIN (*-ErrorStr-*)
- ChangeWindow( ErrorWindow ) ;
- i := 1 ;
- WHILE str[i] <> ENDSTR DO
- BEGIN
- IF (str[i] = LF) THEN Writeln
- ELSE Write( Chr(str[i]) ) ;
- i := i + 1
- END ;
- ChangeWindow( KermitWindow )
- END ; (*-ErrorStr-*)
-
-
- PROCEDURE DebugPacket(mes : MsgString;
- VAR p : Ppack);
- (* Print Debugging Info, into the error window -pt*)
- VAR
- i: Integer ; (* index into data field -pt*)
- BEGIN (*-DebugPacket-*)
- ChangeWindow( ErrorWindow ) ; (* Print all this in error window -pt*)
- Writeln ;
- Write(mes);
- WITH Buf[p] DO
- BEGIN
- Write( '(count:', count-#40:1 ) ; (* local "UnChar" *)
- Write( ') (seq:', seq-#40:1 ) ;
- Writeln( ') (type:', Chr(ptype), ')' );
- (* Write out the data field, straight to the screen -pt*)
- i := 1 ;
- WHILE (data[i] <> ENDSTR) DO
- BEGIN
- Write( Chr(data[i]) ) ;
- i := i + 1
- END ;
- Writeln ;
- (* done -pt*)
- END;
- ChangeWindow( KermitWindow ) (* back to kermit -pt*)
- END; (*-DebugPacket-*)
-
-
- PROCEDURE Verbose(c:MsgString);
- (* Print writeln if verbosity *)
- BEGIN
- IF Verbosity THEN ErrorMsg(c);
- END.
-
- (* <<<KermitGlobals.Pas>>> *)
- MODULE KermitGlobals;
-
- (*)
- * 1-Dec-83.
- * Split the Kermit program file into: KermitGlobals which contains all
- * global information, and Kermit.Pas which is the main program file.
- * this allow all the kermit modules to be used by any other program.
- (*)
-
- EXPORTS
-
- IMPORTS CmdParse FROM CmdParse ;
- IMPORTS SystemDefs FROM SystemDefs ;
-
- CONST
-
-
- (*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*)
- KermitWindow = 1 ; (* Window numbers - See SysInit for their creation -pt*)
- ErrorWindow = 2 ; (* An error window for all messages and errors -pt*)
- FF = Chr(#014) ; (* A form feed to clear the windows -pt*)
- PromptChar = Chr(#032) ; (* PERQ character set: grey arrow head -pt*)
- OK_to_Pop = True ; (* Allow pop-up menus -pt*)
- MaxPopCmds = 10 ; (* Maximum pop-up commands -pt*)
-
- SetCount = 7 ; (* Number of SET commands [pgt001]*)
- SetNot = SetCount+1 ; (* Non-SET command index *)
- SetAmbig = SetCount+2; (* Ambiguous SET command *)
- ShowCount = SetCount+1;(* SET commands plus 'ALL' *)
- ShowNot = ShowCount+1 ;
- ShowAmbig = ShowCount+2 ;
- MainCount = 9 ;
- MainNot = MainCount+1 ;
- MainAmbig = MainCount+2 ;
-
- (*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*)
- return = #015 ;
- formfeed = #014 ;
- controlbar = 28;
-
- { universal manifest constants }
- ENDSTR = -1; (* End-of-string value [pgt001] *)
- MAXSTR = 100; { longest possible string }
- MsgLength = 20; { length of message string -pt}
-
- { ascii character set in decimal }
- BACKSPACE = 8;
- TAB = 9;
- lf = #012 ; (* Line feed/new line *)
- BLANK = 32;
- EXCLAM = 33; { ! }
- DQUOTE = 34; { " }
- SHARP = 35; { # }
- DOLLAR = 36; { $ }
- PERCENT = 37; { % }
- AMPER = 38; { & }
- SQUOTE = 39; { ' }
- ACUTE = SQUOTE;
- LPAREN = 40; { ( }
- RPAREN = 41; { ) }
- STAR = 42; { * }
- PLUS = 43; { + }
- COMMA = 44; { , }
- MINUS = 45; { - }
- DASH = MINUS;
- PERIOD = 46; { . }
- SLASH = 47; { / }
- COLON = 58; { : }
- SEMICOL = 59; { ; }
- LESS = 60; { < }
- EQUALS = 61; { = }
- GREATER = 62; { > }
- QUESTION = 63; { ? }
- ATSIGN = 64; { @ }
- LBRACK = 91; { [ }
- BACKSLASH = 92; { \ }
- ESCAPE = BACKSLASH; { changed - used to be @ }
- RBRACK = 93; { ] }
- CARET = 94; { ^ }
- UNDERLINE = 95; { _ }
- GRAVE = 96; { ` }
- LETA = 97; { lower case ... }
- LETB = 98;
- LETC = 99;
- LETD = 100;
- LETE = 101;
- LETF = 102;
- LETG = 103;
- LETH = 104;
- LETI = 105;
- LETJ = 106;
- LETK = 107;
- LETL = 108;
- LETM = 109;
- LETN = 110;
- LETO = 111;
- LETP = 112;
- LETQ = 113;
- LETR = 114;
- LETS = 115;
- LETT = 116;
- LETU = 117;
- LETV = 118;
- LETW = 119;
- LETX = 120;
- LETY = 121;
- LETZ = 122;
- LBRACE = 123; { left brace }
- BAR = 124; { | }
- RBRACE = 125; { right brace }
- TILDE = 126; { ~ }
-
-
- SOH = 1; (* ascii SOH character *)
- CR = 13; (* CR *)
- DEL = 127; (* rubout *)
-
- DEFEOL = CR ; (* default eoln *)
- DEFTRY = 10; (* default for number of retries *)
- DEFTIMEOUT = 12; (* default time out *)
- MAXPACK = 94; (* max is 94 ~ - ' ' *)
- DEFDELAY = 1; (* delay before sending first init *)
- NUMPARAM = 6; (* number of parameters in init packet *)
- DEFQUOTE = SHARP; (* default quote character *)
- DEFPAD = 0; (* default number OF padding chars *)
- DEFPADCHAR = 0; (* default padding character *)
-
- NumBuffers = 5; (* Number of packet buffers *)
-
- (* packet types *)
-
- TYPEB = 66; (* ord('B') *)
- TYPED = 68; (* ord('D') *)
- TYPEE = 69; (* ord('E') *)
- TYPEF = 70; (* ord('F') *)
- TYPEN = 78; (* ord('N') *)
- TYPES = 83; (* ord('S') *)
- TYPET = 84; (* ord('T') *)
- TYPEY = 89; (* ord('Y') *)
- TYPEZ = 90; (* ord('Z') *)
-
-
-
- TYPE
-
-
- CharBytes = -2..255; (* full 8-bits, with -1 == end-of-string [pgt001]*)
- istring = ARRAY [1..MAXSTR] OF CharBytes;
- MsgString = String[ MsgLength ]; (* String for various messages -pt*)
-
-
- (* Data Types for Kermit *)
-
-
- Packet = RECORD
- mark : CharBytes; (* SOH character *)
- count: CharBytes; (* # of bytes following this field *)
- seq : CharBytes; (* sequence number modulo 64 *)
- ptype: CharBytes; (* d,y,n,s,b,f,z,e,t packet type *)
- data : istring; (* the actual data *)
- (* chksum is last validchar in data array *)
- (* eol is added, not considered part of packet proper *)
- END;
-
- KermitCommand = (Transmit,Receive,SetParm,Invalid);
-
- KermitStates = (FileData,Init,Break,FileHeader,EOFile,Complete,Abort);
-
- Stats = Real ; (* Statistic counting -pt*)
-
- Ppack = 1..NumBuffers;
-
- CType = RECORD
- check: Integer;
- PacketPtr : Integer;
- i : Integer;
- fld : Integer;
- t : CharBytes;
- finished : Boolean;
- restart : Boolean;
- control : Boolean;
- good : Boolean;
- END;
-
- InType = (abortnow,nothing,CRin);
-
- (* Data types for pop-up menus *)
- MyCmds = ARRAY [1..MaxPopCmds] OF String[25] ; (* Menu strings *)
- MyMenu = RECORD
- Head: String[25] ;(* Heading *)
- numcmds: Integer ;(* Number of commands *)
- cmd: MyCmds (* The actual commands *)
- END ;
- MyMenuPtr = ^MyMenu ;
-
-
- VAR
-
-
- done:Boolean;
- bufferoverflow, finis, XOFFState:Boolean;
- ch:Char;
- XON, XOFF:Char;
-
- (* Variables for commands *)
- CmdSpelling, CmdLine: CString ; (* the command and rest of line *)
- CmdIndex: Integer ; (* Index from command parser *)
- Inf: pCmdList ; (* Command file pointer *)
- firstPress: Boolean ;(* Inital call to command parser *)
-
- (* Variables for pop-up menus *)
- MainMenu, (* Main Kermit menu *)
- SetMenu: MyMenuPtr ; (* SET commands *)
- OnOff: CmdArray ; (* For the SET feature ON/OFF *)
-
-
-
- (* SET variables *)
- EscapeChr: Char ; (* CONNECT 'escape' character -pt*)
- EscPrint : Char ; (* Printable verion of this character -pt*)
- BaudRate : String ;
- FileWarning: Boolean ;
- HalfDuplex:Boolean;
- Verbosity: Boolean; (* true to print verbose messages *)
- Debug : Boolean;
- EightBitFile: Boolean ; (* 8-bit flag [pgt001]*)
- (* Varibles for Kermit *)
- dumStr : String ;(* Dummy string -pt*)
- dumCh: Char ; (* A dummy character -pt*)
-
- aline : istring;
- DiskFile : Integer;(* Should be "filedesc" -pt*)
- SaveState: kermitstates;
- MaxTry : Integer;
- n,J : Integer; (* packet number *)
- NumTry : Integer; (* times this packet retried *)
- OldTry : Integer;
- NumPad : Integer; (* padding to send *)
- MyPad : Integer; (* number of padding characters I need *)
- PadChar : CharBytes;
- MyPadChar: CharBytes;
- RunType : KermitCommand;
- State : kermitstates; (* current state of the automaton *)
- MyTimeOut: Integer; (* when i want to be timed out *)
- TheirTimeOut : Integer;
- Delay : Integer;
- SizeRecv, SizeSend : Integer;
- SendEOL, SendQuote : CharBytes;
- myEOL,myQuote: CharBytes;
- NumSendPacks : Integer;
- NumRecvPacks : Integer;
- NumACK : Integer;
- NumNAK : Integer;
- NumACKrecv : Integer;
- NumNAKrecv : Integer;
- NumBADrecv : Integer;
- RunTime: Integer;
- ChInFile, ChInPack : Stats;
-
- Buf : ARRAY [1..NumBuffers] OF packet;
- ThisPacket : Ppack; (* current packet being sent *)
- LastPacket : Ppack; (* last packet sent *)
- CurrentPacket : Ppack; (* current packet received *)
- NextPacket : Ppack; (* next packet being received *)
- InputPacket : Ppack; (* save input to do debug *)
-
- TOPacket : packet; (* Time_Out Packet *)
- OldTime : Double ; (* Clock time -pt*)
- TimeLeft : Integer; (* until Time_Out *)
-
- FromConsole : InType;(* Input from Console during receive *)
-
- PackControl : CType; (* variables for receive packet routine *)
-
-
-
-
- PROCEDURE SYSinit; (* special initialization *)
-
- PROCEDURE SYSfinish; (* System dependent *)
-
- PROCEDURE KermitInit;(* initialize various parameters & defaults *)
-
-
- PROCEDURE ErrorPack(c:MsgString);
- (* Send the other host the an error packet with mesage <c> -pt*)
-
-
- EXCEPTION GotErrorPacket(VAR ErrorMsg: istring) ;
- (*)
- * This is used when procedure "BuildPacket" receives an error packet
- * from the other Host. Handlers in procedures "RecvSwitch" and
- * "SendSwitch" are used to abort the current RECEIVE/SEND command
- * and close any disk files open.
- (*)
-
-
-
- PRIVATE
-
- IMPORTS Screen FROM Screen ;
- IMPORTS PopCmdParse FROM PopCmdParse ;
- IMPORTS IO_Others FROM IO_Others ;
- IMPORTS RS232Baud FROM RS232Baud ;
- IMPORTS Stdio FROM Stdio ;
- IMPORTS KermitUtils FROM KermitUtils ;
- IMPORTS KermitSend FROM KermitSend ;
-
-
- PROCEDURE SYSinit; (* special initialization *)
- BEGIN
- Writeln( FF ) ; (* Clear the entire screen *)
-
- (*---------- PERQ ----------*)
-
- (* Create the windows *)
- CreateWindow(KermitWindow, 0, 0, 767, 700,
- 'PERQ Kermit, Version 2.0') ;
- (* A cursor for the Kermit window *)
- SCurChr( Chr(#177) ) ; (* A black rectangle *)
- SCurOn ; (* Turn it on *)
-
- CreateWindow(ErrorWindow, 0, 701, 767, 322, 'Error and Message Window') ;
-
- ChangeWindow( KermitWindow ) ;
-
- (* Create pop-up menus *)
- New(MainMenu) ;
- WITH MainMenu^ DO
- BEGIN
- Head := 'Kermit' ;
- numcmds := MainCount ;
- cmd[1] := 'CONNECT' ;
- cmd[2] := 'EXIT' ;
- cmd[3] := 'HELP' ;
- cmd[4] := 'QUIT' ;
- cmd[5] := 'RECEIVE' ;
- cmd[6] := 'SEND' ;
- cmd[7] := 'SET' ;
- cmd[8] := 'SHOW' ;
- cmd[9] := 'STATISTICS' ;
- END ; (* with main menu *)
-
- (* ON or OFF *)
- OnOff[1] := 'ON' ;
- OnOff[2] := 'OFF' ;
-
- New(SetMenu) ;
- WITH SetMenu^ DO
- BEGIN
- Head := 'SET commands' ;
- numcmds := SetCount ; (* 7 if we include "ALL" for SHOW cmd *)
- cmd[1] := 'SPEED' ;
- cmd[2] := 'DEBUG' ;
- cmd[3] := 'ESCAPE' ;
- cmd[4] := 'WARNING' ;
- cmd[5] := 'LOCAL' ;
- cmd[6] := 'VERBOSE' ;
- cmd[7] := 'EIGHT-BIT' ; (* [pgt001] *)
- cmd[8] := 'ALL' ; (* <<<< *)
- END ; (* with SET menu *)
-
- (* other initialisation *)
- InitCmdFile(Inf, 0) ;
- InitPopUp ;
- IOCursorMode( TrackCursor ) ;
- firstPress := True ;
-
- (*---------- KERMIT ----------*)
- finis:=False;
- XOFFState:=False;
- XON:=Chr(#021); XOFF:=Chr(#023);
-
- (* SET values -pt*)
- EscapeChr := Chr(#034) ; (* CONNECT escape character ^\ *)
- EscPrint := '\' ; (* Printable version *)
- BaudRate := '9600' ;
- SetBaud( '9600', True ) ;
- HalfDuplex:=False ;
- Verbosity := False; (* default to false / only valid if local *)
- Debug := False;
- EightBitFile := False ; (* [pgt001] *)
- FileWarning := False ;
-
-
- (* Statistic counters *)
- NumSendPacks := 0;
- NumRecvPacks := 0;
- NumACK := 0;
- NumNAK := 0;
- NumACKrecv := 0;
- NumNAKrecv := 0;
- NumBADrecv := 0;
-
- ChInFile := 0.0; (* Statsistics are now reals. -pt*)
- ChInPack := ChInFile;
-
- (* Other values *)
- NumPad := DEFPAD; (* set defaults *)
- MyPad := DEFPAD;
- PadChar := DEFPADCHAR;
- MyPadChar := DEFPADCHAR;
- TheirTimeOut := DEFTIMEOUT;
- MyTimeOut := DEFTIMEOUT;
- Delay := DEFDELAY;
- SizeRecv := MAXPACK;
- SizeSend := MAXPACK;
- SendEOL := DEFEOL;
- MyEOL := DEFEOL;
- SendQuote := DEFQUOTE;
- MyQuote := DEFQUOTE;
- MaxTry := DEFTRY;
-
- END;
-
- PROCEDURE SYSfinish; (* System dependent *)
- BEGIN
- Writeln( FF ) ;
- Dispose( MainMenu ) ;
- Dispose( SetMenu ) ;
- DstryCmdFile( Inf ) ;
- END;
-
-
- PROCEDURE KermitInit; (* initialize various parameters & defaults *)
- BEGIN
- n := 0;
-
- RunType := invalid;
- DiskFile := StdIOError; (* to indicate not open yet *)
-
- ThisPacket := 1;
- LastPacket := 2;
- CurrentPacket := 3;
- NextPacket := 4;
- InputPacket := 5;
-
- WITH TOPacket DO
- BEGIN
- count := 3;
- seq := 0;
- ptype := TYPEN;
- data[1] := ENDSTR;
- END;
-
- FROMCONSOLE:=NOTHING;
-
- END;
-
-
-
-
- PROCEDURE CtoS(x:MsgString; VAR s:istring);
- (* convert constant to STIP string *)
- VAR
- i : Integer;
- BEGIN
- FOR i:=1 TO Length(x) DO
- s[i] := Ord(x[i]);
- s[Length(x)+1] := ENDSTR;
- END;
-
- PROCEDURE ErrorPack(c:MsgString);
- (* output Error packet if necessary -- then exit *)
- BEGIN
- WITH Buf[ThisPacket] DO
- BEGIN
- seq := n;
- ptype := TYPEE;
- CtoS(c,data);
- count := ilength(data);
- END;
- SendPacket;
- Writeln('%Message to other Host: ', c)
- END.
-
- (* <<<KermitHelp.Pas>>> *)
- MODULE KermitHelp ;
-
- EXPORTS
-
- PROCEDURE DoHelp ;
-
- PRIVATE
-
- IMPORTS KermitUtils FROM KermitUtils ;
-
-
- PROCEDURE DoHelp ;
- (*)
- * Print out the Kermit help info. Use the utilities to write the
- * commands in inverse video.
- (*)
- BEGIN (*-DoHelp-*)
- Writeln( Chr(#014) ) ; (* Clear the screen *)
- Inverse( TRUE ) ; Writeln(' CONNECT'); Inverse( FALSE ) ;
- Writeln('Connect the PERQ to another host. This allows you to log into other');
- Writeln('systems.');
- Inverse( TRUE ) ; Writeln(' EXIT'); Inverse( FALSE ) ;
- Writeln('Exit from KERMIT back to the PERQ operating system.');
- Inverse( TRUE ) ; Writeln(' HELP'); Inverse( FALSE ) ;
- Writeln('Print instructions on various commands available in KERMIT.');
- Inverse( TRUE ) ; Writeln(' QUIT'); Inverse( FALSE ) ;
- Writeln('Same as EXIT.');
- Inverse( TRUE ) ; Writeln(' RECEIVE <optional file-name>'); Inverse( FALSE ) ;
- Writeln('Receive a file group from the remote host. If an incoming file name');
- Writeln('is not legal, then attempt to transform it to a similar legal name,');
- Writeln('e.g. by deleting illegal or excessive characters. If the file');
- Writeln('already exists, it will be superceded unless WARNING is ON.');
- Inverse( TRUE ) ; Writeln(' SEND <file-specification>'); Inverse( FALSE ) ;
- Writeln('Sends a file from the PERQ to the remote host. The name of the file');
- Writeln('is passed to the remote host in a special control packet, so that the');
- Writeln('remote host can store it with the same name. Wildcards are not yet');
- Writeln('supported.');
- Inverse( TRUE ) ; Writeln(' SET <keyword>'); Inverse( FALSE ) ;
- Writeln('Change various system-dependent parameters. For a list of keywords,');
- Writeln('type SET ?.');
- Inverse( TRUE ) ; Writeln(' SHOW <keyword>'); Inverse( FALSE ) ;
- Writeln('Display various system-dependent parameters established by the SET');
- Writeln('command. For a list of available keywords type SHOW ?.');
- Inverse( TRUE ) ; Writeln(' STATISTICS'); Inverse( FALSE ) ;
- Writeln('Display some statistics about Kermit''s operations.');
-
- Writeln
- END (*-DoHelp-*) .
-
- (* <<<KermitParms.Pas>>> *)
- MODULE KermitParms ;
-
- (* Deal with various Kermit Parameters: Set and Show *)
- (* 29-Nov-83 Allow eight bit file transfer [pgt001] *)
-
-
- EXPORTS
-
-
- PROCEDURE SetParameters ;
- PROCEDURE DoShow ;
-
-
-
-
- PRIVATE
-
- IMPORTS KermitGlobals FROM KermitGlobals ;
- IMPORTS RS232Baud FROM RS232Baud ;
- IMPORTS CmdParse FROM CmdParse ;
- IMPORTS PopCmdParse FROM PopCmdParse ;
- IMPORTS PopUp FROM PopUp ;
- IMPORTS Perq_String FROM Perq_String ;
-
-
- PROCEDURE SetParameters ;
- (* Set Kermit flags and other communications features -pt*)
- VAR
- id, parm: String ; (* SET identifier and (possible) parameter *)
- switch, parmsw: Boolean ; (* Switch flags for feature and parameter *)
- index: Integer ; (* Command index *)
-
- PROCEDURE DoBaudRate( NewRate: String ) ;
- (* Try to set a new baud rate for the RS232 port *)
- CONST
- InputEnable = True ; (* Enable RS232 input *)
-
- HANDLER BadBaudRate ;
- BEGIN (*-BadBaudRate-*)
- Writeln('?Bad baud rate given: ', NewRate) ;
- EXIT( DoBaudRate )
- END ; (*-BadBaudRate-*)
-
- BEGIN (*-DoBaudRate-*)
- IF (NewRate = '') THEN Writeln('%No value for SET SPEED')
- ELSE
- BEGIN
- (* set the rate *)
- SetBaud( NewRate, InputEnabled) ;
- (* Here if that was successful, save the new rate *)
- BaudRate := NewRate
- END
- END ; (*-DoBaudRate-*)
-
- FUNCTION MkOctal( src: String ): Integer ;
- (* convert the octal number in the source string into a number *)
- VAR
- i, sum: Integer ; (* index and summation value *)
- ok: Boolean ; (* loop control *)
- BEGIN (*-MkOctal-*)
- ok := True ; i := 1 ; sum := 0 ;
- WHILE ok DO
- IF NOT (src[i] IN ['0'..'7']) THEN ok := False (* reached non-octal *)
- ELSE
- BEGIN
- sum := sum*8 + Ord(src[i]) - #60 ;
- i := i + 1 ;
- ok := (i <= Length(src)) (* exit test *)
- END ;
- MkOctal := sum
- END ; (*-MkOctal-*)
-
- PROCEDURE DoEscChr( OctalStr: String ) ;
- (* try to set a new CONNECT escape character *)
- (* OctalStr contains the string representation of the octal number *)
- VAR
- val: Integer ; (* The escape character's ordinal *)
- BEGIN (*-DoEscChr-*)
- IF (OctalStr = '') THEN
- Writeln('?SET ESCAPE requires an octal number')
- ELSE
- IF (OctalStr[1] IN ['0'..'7']) THEN
- BEGIN
- val := MkOctal( OctalStr ) ; (* Get the value *)
- IF (val = 0) OR (val > #037) THEN
- Writeln('%Illegal ESCAPE character value: ', val:1:8)
- ELSE
- BEGIN
- (* set the character and its printable version *)
- EscapeChr := Chr( val ) ;
- EscPrint := Chr( val + #100 )
- END
- END (* octal digit *)
- ELSE
- Writeln('?Non-Octal digit in SET ESCAPE parameter')
- END ; (*DoEscChr-*)
-
- PROCEDURE DoOnOff(VAR flag: Boolean) ;
- (*)
- * For the set feature with menu index <index> see if <parm> is
- * either ON or OFF. If so, set <flag> to True or False, resp.
- * Otherwise write error message and leave <flag> alone.
- (*)
- VAR
- val: Integer ; (* Value of table search ON/OFF *)
- BEGIN (*-DoOnOff-*)
-
- ConvUpper( parm ) ; (* MUST be upper case *)
-
- IF (parm = '') THEN val := 3 (* not ON/OFF *)
- ELSE
- val := UniqueCmdIndex(parm, OnOff, 2) ;
-
- CASE val OF
- 1: flag := True ; (* ON *)
- 2: flag := False ; (* OFF *)
- 3: Writeln('%SET ', SetMenu^.Cmd[index], ' requires ON or OFF') ;
- 4: Writeln('%Ambiguous ON or OFF in SET ', SetMenu^.Cmd[index] )
- END ; (* case *)
-
- END ; (*-DoOnOff-*)
-
- PROCEDURE SetHelp ;
- (* Provide help information for the command SET ? *)
- BEGIN (*-SetHelp-*)
- Writeln ;
- Writeln('The following features are available with the SET command :') ;
- Writeln ;
- Writeln('SPEED <rate> Change the PERQ''s line speed') ;
- Writeln('DEBUG ON|OFF Print debug information') ;
- Writeln('ESCAPE <octal> Change the CONNECT escape character') ;
- Writeln('WARNING ON|OFF Give warning when overwriting existing files') ;
- Writeln('LOCAL ON|OFF Echo CONNECT typein locally') ;
- Writeln('VERBOSE ON|OFF Display Kermit''s actions') ;
- Writeln('EIGHT-BIT ON|OFF Allow eight bit file transfer');(*[pgt001]*)
- Writeln
- END ; (*-SetHelp-*)
-
- BEGIN (*-SetParameter-*)
- (* If the command line is empty, prompt user *)
- IF (CmdLine = '') THEN
- BEGIN
- Write('Kermit-SET', PromptChar) ;
- Readln( CmdLine )
- END ;
-
- (* get the first identifier from the line *)
- dumCh := NextIDString( CmdLine, id, switch ) ;
- (* and a possible parameter *)
- dumCh := NextIDString( CmdLine, parm, parmsw ) ;
-
- IF (id = '') THEN (* nothing - return *)
- ELSE
- IF switch OR parmsw THEN Writeln('%SET does not take switches')
- ELSE
- IF (id[1] = '?') THEN SetHelp
- ELSE
- BEGIN
-
- index := PopUniqueCmdIndex(id, RECAST(SetMenu, pNameDesc) ) ;
- (* What was the command ? *)
- CASE index OF
- 1: DoBaudRate( parm ) ; (* SPEED *)
- 2: DoOnOff( debug ) ; (* DEBUG *)
- 3: DoEscChr( parm ) ; (* ESCAPE *)
- 4: DoOnOff( FileWarning ) ; (* WARNING *)
- 5: DoOnOff( HalfDuplex ) ; (* LOCAL *)
- 6: DoOnOff( Verbosity ) ; (* VERBOSE *)
- 7: DoOnOff( EightBitFile ) ; (* EIGHT-BIT [pgt001]*)
- 8: Writeln('%Not a SET feature: ', id) ;
- 9: Writeln('%Ambiguous SET feature: ', id)
- END ; (* case *)
- END (* else *)
-
- END ; (*-SetParameter-*)
-
-
-
- PROCEDURE DoShow ;
- (* Show the Kermit flags and parameters *)
- VAR
- flag: ARRAY [Boolean] OF String[3] ; (* OF or OFF *)
- id: String ; (* identifier *)
- switch: Boolean ; (* SHOW /xxx flag *)
- i: Integer ; (* Index *)
-
- PROCEDURE Feature( index: Integer ) ;
- (* write a single feature - Index into SetMenu *)
- BEGIN (*-Index-*)
- CASE index OF
- 1: Writeln('Baud rate ', BaudRate) ;
- 2: Writeln('Debug ', flag[debug]) ;
- 3: Writeln('Escape chr ^', EscPrint,' (Octal ', Ord(EscapeChr):1:8, ')') ;
- 4: Writeln('Warning ', flag[FileWarning]) ;
- 5: Writeln('Local ', flag[HalfDuplex]) ;
- 6: Writeln('Verbose ', flag[Verbosity]) ;
- 7: Writeln('Eight-Bit ', flag[EightBitFile]) (*[pgt001]*)
- END (* case *)
- END ; (*-Feature-*)
-
- BEGIN (*-DoShow-*)
-
- Writeln ;
- flag[True] := 'ON' ;
- flag[False]:= 'OFF' ;
-
- (* get the show feature *)
- dumCh := NextIDString(CmdLine, id, switch) ;
- IF (id = '') THEN id := 'ALL' ; (* Default *)
-
- IF switch THEN
- Writeln('%SHOW does not take switches')
- ELSE
- IF (id[1] = '?') THEN (* simple help *)
- BEGIN
- Writeln('One of the following :-') ;
- WITH SetMenu^ DO
- FOR i := 1 TO ShowCount DO (* include 'ALL' *)
- Writeln( Cmd[i] )
- END
- ELSE (* find feature's index *)
- BEGIN
- (* add 'ALL' to the search *)
- SetMenu^.numcmds := ShowCount ;
- i := PopUniqueCmdIndex( id, RECAST(SetMenu, pNameDesc) ) ;
- SetMenu^.numcmds := SetCount ;
-
- IF (i <= SetCount) THEN Feature( i )
- ELSE
- IF (i = ShowCount) THEN
- BEGIN
- FOR i := 1 TO SetCount DO Feature(i)
- END
- ELSE
- IF (i = ShowNot) THEN
- Writeln('?Not a SHOW parameter: ', id)
- ELSE
- IF (i = ShowAmbig) THEN
- Writeln('%Ambiguous SHOW parameter: ', id)
- END ; (* else *)
- Writeln
- END . (*-DoShow-*)
-
- (* <<<KermitRecv.Pas>>> *)
- MODULE KermitRecv ;
-
- (* 29-Nov-83 Allow eight bit file transfer (c.f. sopen call) [pgt001] *)
- (* 30-Nov-83 During a receive clear the screen and show characters *)
- (* and packets received. [pgt002] *)
-
-
- EXPORTS
-
- FUNCTION ReceiveACK : (* Returning *) Boolean;
- PROCEDURE RecvSwitch; (* this procedure is the main receive routine *)
-
-
- PRIVATE
-
- IMPORTS KermitGlobals FROM KermitGlobals ;
- IMPORTS KermitUtils FROM KermitUtils ;
- IMPORTS Stdio FROM Stdio ;
- IMPORTS KermitError FROM KermitError ;
- IMPORTS KermitSend FROM KermitSend ; (* for sending ACKs and NAKs, etc *)
- IMPORTS Screen FROM Screen ; (* screen control [pgt002] *)
-
-
- VAR
- OldChInFile: Stats ; (* Characters in file [pgt002]*)
- BadPackets: Integer ; (* Bad packet count for this recv [pgt002]*)
-
-
- {$RANGE-} (* Range checks off to see if it runs faster (16-Jan-84)*)
-
-
- PROCEDURE Field1; (* Count *)
- VAR
- test: Boolean;
- BEGIN
- WITH Buf[NextPacket] DO
- BEGIN
- WITH PackControl DO
- BEGIN
- Buf[InputPacket].count := t;
- count := UnChar(t);
- test := (count >= 3) OR (count <= SizeRecv-2);
- (* IF (NOT test) AND Debug THEN ErrorMsg('Bad count'); *)
- good := good AND test;
- END;
- END;
- END;
-
- PROCEDURE Field2; (* Packet Number *)
- VAR
- test : Boolean;
- BEGIN
- WITH Buf[NextPacket] DO
- BEGIN
- WITH PackControl DO
- BEGIN
- Buf[InputPacket].seq := t;
- seq := UnChar(t);
- test := (seq >= 0) OR (seq <= 63);
- (* IF (NOT test) AND Debug THEN ErrorMsg('Bad seq number'); *)
- good := test AND good;
- END;
- END;
- END;
-
- PROCEDURE Field3; (* Packet Type *)
- VAR
- test : Boolean;
- BEGIN
- WITH Buf[NextPacket] DO
- BEGIN
- WITH PackControl DO
- BEGIN
- ptype := t;
- Buf[InputPacket].ptype := t;
- test := IsValidPType(ptype);
- (* IF (NOT test) AND Debug THEN ErrorMsg('Bad Packet Type'); *)
- good := test AND good;
- END;
- END;
- END;
-
- PROCEDURE Field4; (* Data *)
- BEGIN
- WITH PackControl DO
- BEGIN
- PacketPtr := PacketPtr+1;
- Buf[InputPacket].data[PacketPtr] := t;
- WITH Buf[NextPacket] DO
- BEGIN
- IF (t = MyQuote) THEN (* character is quote *)
- BEGIN
- IF control THEN (* quote ,quote *)
- BEGIN
- data[i] := MyQuote;
- i := i+1;
- control := False;
- END
- ELSE (* set control on *)
- control := True
- END
- ELSE (* not quote *)
- IF control THEN (* convert to control *)
- BEGIN
- data[i] := ctl(t);
- i := i+1;
- control := False
- END
- ELSE (* regular data *)
- BEGIN
- data[i] := t;
- i := i+1;
- END;
- END;
- END;
- END;
-
- PROCEDURE Field5; (* Check Sum *)
- VAR
- test : Boolean;
- BEGIN
- WITH PackControl DO
- BEGIN
- PacketPtr := PacketPtr +1;
- Buf[InputPacket].data[PacketPtr] := t;
- Buf[InputPacket].data[PacketPtr + 1] := ENDSTR;
- check := CheckFunction(check);
- check := MakeChar(check);
- test := (t=check);
- IF (NOT test) AND Debug THEN ErrorMsg('Bad CheckSum');
- good := test AND good;
- Buf[NextPacket].data[i] := ENDSTR;
- finished := True; (* set finished *)
- END;
- END;
-
- PROCEDURE BuildPacket;
- (* receive packet & validate checksum *)
- VAR
- temp : Ppack;
- BEGIN
- WITH PackControl DO
- BEGIN
- WITH Buf[NextPacket] DO
- BEGIN
- IF (t <> ENDSTR) THEN
- IF restart THEN
- BEGIN
- (* read until get SOH marker *)
- IF (t = SOH) THEN
- BEGIN
- finished := False; (* set varibles *)
- control := False;
- good := True;
- seq := -1; (* set return values to bad packet *)
- ptype := QUESTION;
- data[1] := ENDSTR;
- data[MAXSTR] := ENDSTR;
- restart := False;
- fld := 0;
- i := 1;
- PacketPtr := 0;
- check := 0;
- END;
- END
- ELSE (* Not restart -pt*) (* have started packet *)
- BEGIN
- IF (t = SOH) THEN (* check for restart or EOL *)
- restart := True
- ELSE
- IF (t = myEOL) THEN
- BEGIN
- finished := True;
- good := False;
- END
- ELSE
- BEGIN
- CASE fld OF
- (* increment field number *)
- 0: fld := 1;
- 1: fld := 2;
- 2: fld := 3;
- 3:
- IF (count = 3) (* no data *)
- THEN fld := 5
- ELSE fld := 4;
- 4:
- IF (PacketPtr>=count-3) (* end of data *)
- THEN fld := 5;
- END (* case *);
- IF (fld <> 5)
- THEN check := check+t; (* add into checksum *)
-
- CASE fld OF
- 1: Field1;
- 2: Field2;
- 3: Field3;
- 4: Field4;
- 5: Field5;
- END;
- (* case *)
- END;
- END;
-
- IF finished THEN
- BEGIN
- IF (ptype = TYPEE) AND good THEN (* error_packets *)
- BEGIN
- SendACK(n); (* send ACK *)
-
- RAISE GotErrorPacket( data ) ; (* ********** *)
-
- END;
- NumRecvPacks := NumRecvPacks+1;
- IF Debug THEN
- BEGIN
- DebugPacket('Received: ',InputPacket);
- IF good THEN ErrorMsg('Is Good');
- END;
-
- temp := CurrentPacket;
- CurrentPacket := NextPacket;
- NextPacket := temp;
- END;
- END;
- END;
- END;
-
- FUNCTION ReceivePacket: Boolean;
- BEGIN
- WITH PackControl DO
- BEGIN
- StartTimer;
- good := False ;
- finished := False;
- restart := True;
- (* No Keyboard Interupt - Set by ^C handler -pt*)
- FromConsole := nothing;
- REPEAT
- t := GetIn;
-
- CheckTimer ;
- IF (FromConsole = abortnow) THEN
- BEGIN
- State := ABORT ;
- ReceivePacket := False ;
- EXIT( ReceivePacket )
- END;
-
- BuildPacket;
- UNTIL finished OR (TimeLeft <= 0);
- IF (TimeLeft <= 0) THEN
- BEGIN
- Buf[CurrentPacket] := TOPacket;
- restart := True;
- IF NOT ((RunType=Transmit) AND (State=Init)) THEN
- BEGIN
- ErrorInt('%Timed out ', n)
- END;
- END;
- StopTimer;
- IF NOT good THEN BadPackets := BadPackets + 1 ;
- ReceivePacket := good;
- END;
- END;
-
- FUNCTION ReceiveACK : (* Returning *) Boolean;
- (* receive ACK with correct number *)
- VAR
- Ok: Boolean;
- BEGIN
- Ok := ReceivePacket;
- WITH Buf[CurrentPacket] DO
- BEGIN
- IF (ptype = TYPEY) THEN NumACKrecv := NumACKrecv+1
- ELSE
- IF (ptype = TYPEN) THEN NumNAKrecv := NumNAKrecv+1
- ELSE
- NumBadrecv := NumBadrecv +1;
- (* got right one ? *)
- ReceiveACK := ( Ok AND (ptype=TYPEY) AND (n=seq))
- END;
- END;
-
-
- PROCEDURE GetFile((* Using *) data:istring);
- (* create file from fileheader packet *)
- VAR
- len: Integer;
-
- PROCEDURE Strip( var name: istring ) ;
- (* Strip off any blanks (usually trailing) from the file name *)
- VAR i, newpos: integer ;
- BEGIN (*-Strip-*)
- newpos := 1 ; (* this is the new character position for non-blanks *)
- FOR i := 1 TO ilength(name) DO
- IF (name[i] = blank) THEN (* skip it by not incrementing "newpos" *)
- ELSE
- BEGIN (* restore character *)
- name[newpos] := name[i] ;
- newpos := newpos + 1
- END ;
-
- name[newpos] := ENDSTR
- END ; (*-Strip-*)
-
- BEGIN
- WITH Buf[CurrentPacket] DO
- BEGIN
- IF (DiskFile = StdIOError) THEN (* check if we already have a file *)
- BEGIN
- Strip( data ) ; (* remove any blanks *)
- IF Verbosity THEN
- BEGIN
- ErrorMsg ('Creating file: ');
- ErrorStr(data);
- END;
- IF Exists(data) AND FileWarning THEN
- BEGIN
- ErrorMsg('File already exists ');
- ErrorStr(data);
- ErrorMsg('Creating: ');
- (* Make it <file>.A *)
- len := ilength(data) + 1 ; (* first free char pos *)
- data[len] := PERIOD ;
- data[len+1] := leta ;
- data[len+2] := ENDSTR;
- ErrorStr(data)
- END;
- IF EightBitFile THEN
- DiskFile := Sopen(data,StdIO8Write)
- ELSE
- DiskFile := Sopen(data,StdIOWrite);
- END;
- IF (Diskfile <= StdIOError) THEN ErrorPack('Cannot create file ');
- END;
- END;
-
- PROCEDURE ReceiveInit;
- (* receive init packet *)
- (* respond with ACK and our parameters *)
- BEGIN
- IF (NumTry > MaxTry) THEN
- BEGIN
- State := Abort;
- ErrorMsg('Cannot receive init');
- END
- ELSE
- BEGIN
- Verbose('Receiving Init');
- NumTry := NumTry+1;
- IF ReceivePacket
- AND (Buf[CurrentPacket].ptype = TYPES) THEN
- BEGIN
- WITH Buf[CurrentPacket] DO
- BEGIN
- n := seq;
- DeCodeParm(data);
- END;
-
- (* now send mine *)
- WITH Buf[ThisPacket] DO
- BEGIN
- count := NUMPARAM;
- seq := n;
- Ptype := TYPEY;
- EnCodeParm(data);
- END;
-
- SendPacket;
-
- NumACK := NumACK+1;
- State := FileHeader;
- OldTry := NumTry;
- NumTry := 0;
- n := (n+1) MOD 64
- END
- ELSE
- BEGIN
- IF Debug THEN ErrorMsg('Received Bad init');
- SendNAK(n);
- END;
- END;
- END;
-
- PROCEDURE DataToFile; (* output to file *)
- VAR
- len,i : Integer;
- temp : istring;
- BEGIN
- WITH Buf[CurrentPacket] DO
- BEGIN
- len := ilength(data);
- ChInFile := ChInFile + len ;
- PutStr(data,DiskFile)
- END;
- END;
-
- PROCEDURE Dodata; (* Process Data packet *)
-
- BEGIN
- WITH Buf[CurrentPacket] DO
- BEGIN
- IF ( seq = ((n + 63) MOD 64)) THEN
- BEGIN (* data last one *)
- IF (OldTry > MaxTry) THEN (* number of tries? *)
- BEGIN
- State := Abort;
- ErrorMsg('Old data - Too many');
- END
- ELSE
- BEGIN
- SendACK(seq);
- NumTry := 0;
- END;
- END
- ELSE
- BEGIN (* data - this one *)
- IF (n <> seq) THEN SendNAK(n)
- ELSE
- BEGIN
- SendACK(n); (* ACK *)
- DataToFile;
- OldTry := NumTry;
- NumTry := 0;
- n := (n+1) MOD 64;
- END;
- END;
- END;
- END;
-
- PROCEDURE DoFileLast; (* Process File Packet *)
- BEGIN (* File header - last one *)
- IF (OldTry > MaxTry) THEN (* tries ? *)
- BEGIN
- State := Abort;
- ErrorMsg('Old file - Too many ');
- END
- ELSE
- BEGIN
- OldTry := OldTry+1;
- WITH Buf[CurrentPacket] DO
- BEGIN
- IF (seq = ((n + 63) MOD 64)) THEN (* packet number *)
- BEGIN (* send ACK *)
- SendACK(seq);
- NumTry := 0
- END
- ELSE
- BEGIN
- SendNAK(n); (* NAK *)
- END;
- END;
- END;
- END;
-
- PROCEDURE DoEOF; (* Process EOF packet *)
- BEGIN (* EOF - this one *)
- IF (Buf[CurrentPacket].seq <> n) THEN (* packet number ? *)
- SendNAK(n) (* NAK *)
- ELSE
- BEGIN (* send ACK *)
- SendACK(n);
- Sclose(DiskFile); (* close file *)
- DiskFile := StdIOError;
- OldTry := NumTry;
- NumTry := 0;
- n := (n+1) MOD 64; (* next packet *)
- State := FileHeader; (* change state *)
- END;
- END;
-
- PROCEDURE ReceiveData; (* Receive data packets *)
- VAR
- strend: Integer;
- packetnum: istring;
- good : Boolean;
-
- BEGIN
- IF (NumTry > MaxTry) THEN (* check number of tries *)
- BEGIN
- State := Abort;
- ErrorInt('Recv data -Too many ', n)
- END
- ELSE
- BEGIN
- NumTry := NumTry+1; (* increase number of tries *)
- good := ReceivePacket; (* get packet *)
- WITH Buf[CurrentPacket] DO
- BEGIN
- IF Verbosity THEN
- BEGIN
- ErrorInt('Receiving (Data) ', Buf[CurrentPacket].seq);
- END ;
-
- IF ((ptype = TYPED) OR (ptype=TYPEZ)
- OR (ptype=TYPEF)) AND good THEN (* check type *)
- CASE ptype OF
- TYPED: DoData;
- TYPEF: DoFileLast;
- TYPEZ: DoEOF;
- END (* case *)
- ELSE
- BEGIN
- Verbose('Expected data pack');
- SendNAK(n);
- END;
- END;
- END;
- END;
-
- PROCEDURE DoBreak; (* Process Break packet *)
- BEGIN (* Break transmission *)
- IF (Buf[CurrentPacket].seq <> n) THEN (* packet number ? *)
- SendNAK(n) (* NAK *)
- ELSE
- BEGIN (* send ACK *)
- SendACK(n) ;
- State := Complete (* change state *)
- END
- END;
-
- PROCEDURE DoFile; (* Process file packet *)
- BEGIN (* File Header *)
- WITH Buf[CurrentPacket] DO
- BEGIN
- IF (seq <> n) THEN (* packet number ? *)
- SendNAK(n) (* NAK *)
- ELSE
- BEGIN (* send ACK *)
- SendACK(n);
- ChInFile := ChInFile + ilength(data) ;
- GetFile(data); (* get file name *)
- OldTry := NumTry;
- NumTry := 0;
- n := (n+1) MOD 64; (* next packet *)
- State := FileData; (* change state *)
- END;
- END;
- END;
-
- PROCEDURE DoEOFLast; (* Process EOF Packet *)
- BEGIN (* End Of File Last One*)
- IF (OldTry > MaxTry) THEN (* tries ? *)
- BEGIN
- State := Abort;
- ErrorMsg('Old EOF - Too many');
- END
- ELSE
- BEGIN
- OldTry := OldTry+1;
- WITH Buf[CurrentPacket] DO
- BEGIN
- IF (seq =((n + 63 ) MOD 64)) THEN (* packet number *)
- BEGIN (* send ACK *)
- SendACK(seq);
- Numtry := 0
- END
- ELSE
- BEGIN
- SendNAK(n); (* NAK *)
- END
- END;
- END;
- END;
-
- PROCEDURE DoInitLast;
- BEGIN (* Init Packet - last one *)
- IF (OldTry > MaxTry) THEN (* number of tries? *)
- BEGIN
- State := Abort;
- ErrorMsg('Old init - Too many');
- END
- ELSE
- BEGIN
- OldTry := OldTry+1;
- (* packet number *)
- IF (Buf[CurrentPacket].seq = ((n + 63) MOD 64)) THEN
- BEGIN (* send ACK *)
- WITH Buf[ThisPacket] DO
- BEGIN
- count := NUMPARAM;
- seq := Buf[CurrentPacket].seq;
- ptype := TYPEY;
- EnCodeParm(data);
- END;
- SendPacket;
- NumACK := NumACK+1;
- NumTry := 0;
- END
- ELSE
- BEGIN
- SendNAK(n); (* NAK *)
- END;
- END;
- END;
-
- PROCEDURE ReceiveFile; (* receive file packet *)
- VAR
- good: Boolean;
-
- BEGIN
- IF (NumTry > MaxTry) THEN (* check number of tries *)
- BEGIN
- State := Abort;
- ErrorMsg('Recv file - Too many');
- END
- ELSE
- BEGIN
- NumTry := NumTry+1; (* increase number of tries *)
- good := ReceivePacket; (* get packet *)
- WITH Buf[CurrentPacket] DO
- BEGIN
- IF Verbosity THEN BEGIN
- ErrorInt('Receiving (File) ', seq)
- END;
-
- (* Set up for new file [pgt002] *)
- OldChInFile := ChInFile ; (* Start value *)
- BadPackets := 0 ;
-
- SSetCursor(250, 100) ;
- Write('File: ');
- PutStr(data,stdout);
- Write(' ':10) ; (* blank the end of any other names *)
-
- IF ((ptype = TYPES) OR (ptype=TYPEZ)
- OR (ptype=TYPEF) OR (ptype=TYPEB)) (* check type *)
- AND good THEN
- CASE ptype OF
- TYPES: DoInitLast;
- TYPEZ: DoEOFLast;
- TYPEF: DoFile;
- TYPEB: DoBreak;
- END (* case *)
- ELSE
- BEGIN
- IF Debug THEN ErrorMsg('Expected File Pack');
- SendNAK(n);
- END;
- END;
- END;
- END;
-
-
- PROCEDURE RecvSwitch; (* this procedure is the main receive routine *)
-
- HANDLER GotErrorPacket( VAR msg: istring ) ;
- (* Handle any error packets reveived. Write msg and exit *)
- BEGIN
- Inverse( TRUE ) ;
- Writeln ;
- Writeln('?RECV received error packet from other Host');
- putstr(msg, STDOUT) ;
- Writeln ;
- Inverse( FALSE ) ;
- SClose( DiskFile ) ; (* Close the file, if open *)
- State := Abort ;
- EXIT( RecvSwitch )
- END ;
-
- BEGIN
- State := Init;
- NumTry := 0;
-
- OldChInFile := ChInFile ; (* Start value *)
- BadPackets := 0 ;
-
- (* set up the progress reports (c.f. ReceiveFile too) [pgt002] *)
- IF NOT Verbosity THEN
- BEGIN
- SPutChr(FF) ; (* clear the screen *)
- SSetCursor(200, 150); Write( 'Current Packet' );
- SSetCursor(200, 170); Write( 'Characters received' );
- SSetCursor(200, 190); Write( 'Bad packets received' )
- END ;
-
-
- REPEAT
-
- (* Each time thru' the loop print the values [pgt002] *)
- IF NOT Verbosity THEN
- BEGIN
- SSetCursor(410, 150); Write( n:8 ) ;
- SSetCursor(410, 170); Write( (ChInFile-OldChInFile):10:0 ) ;
- SSetCursor(410, 190); Write( BadPackets:8 )
- END ;
-
-
- CASE State OF
- FileData: ReceiveData;
- Init: ReceiveInit;
- Break: (* nothing *);
- FileHeader: ReceiveFile;
- EOFile: (* nothing *);
- Complete: (* nothing *);
- Abort: (* nothing *);
- END; (* case *)
-
- UNTIL ( State = Abort ) OR ( State = Complete );
-
- SSetCursor(10, 250) ;
- Writeln
- END.
-
- (* <<<KermitSend>>> *)
- MODULE KermitSend ;
-
- (* 29-Nov-83 Allow eight bit file transfer (c.f. sopen call) [pgt001] *)
-
-
- EXPORTS
-
- PROCEDURE SendPacket;
- PROCEDURE SendACK((* Using *) n:Integer); (* send ACK packet *)
- PROCEDURE SendNAK((* Using *) n:Integer); (* send NAK packet *)
- PROCEDURE SendSwitch;
-
-
-
-
- PRIVATE
-
- IMPORTS KermitGlobals FROM KermitGlobals ;
- IMPORTS KermitUtils FROM KermitUtils ;
- IMPORTS Stdio FROM Stdio ;
- IMPORTS KermitError FROM KermitError ;
- IMPORTS KermitRecv FROM KermitRecv ; (* for receiving ACKs and NAKs *)
- IMPORTS UtilProgress FROM UtilProgress ;
- IMPORTS Sleep FROM Sleep ;
-
-
- {$RANGE-} (* Range checks off 16-Jan-84 *)
-
-
-
-
- VAR
- DataSendCount: Integer ; (* counter for progress *)
-
-
- PROCEDURE PutOut( p : Ppack); (* Output Packet *)
- (* Use direct calls to XmtChar to send the characters -pt*)
- VAR
- i : Integer;
- BEGIN
- IF (NumPad > 0) THEN
- FOR i := 1 TO NumPad DO
- XmtChar( Chr(PadChar) );
- WITH Buf[p] DO
- BEGIN
- XmtChar( Chr(mark) );
- XmtChar( Chr(count) );
- XmtChar( Chr(seq) );
- XmtChar( Chr(ptype) );
- FOR i := 1 TO ilength(data) DO
- XmtChar( Chr(data[i]) );
- END;
- END;
-
-
- PROCEDURE ReSendPacket;
- (* re -sends previous packet *)
- BEGIN
- NumSendPacks := NumSendPacks+1;
- ChInPack := ChInPack + NumPad + UnChar(Buf[LastPacket].count) + 3 ;
- IF Debug
- THEN DebugPacket('Re-Sending: ',LastPacket);
- PutOut(LastPacket);
- END;
-
- PROCEDURE SendPacket;
-
- (* expects count as length of data portion *)
- (* and seq as number of packet *)
- (* builds & sends packet *)
- VAR
- i,len,chksum : Integer;
- temp : Ppack;
- BEGIN
- IF (NumTry <> 1) AND (RunType = Transmit) THEN
- ReSendPacket
- ELSE
- BEGIN
- WITH Buf[ThisPacket] DO
- BEGIN
- mark :=SOH; (* mark *)
- len := count; (* save length *)
- count := MakeChar(len+3); (* count = 3+length of data *)
- seq := MakeChar(seq); (* seq number *)
- chksum := count + seq + ptype;
- IF (len > 0) THEN (* is there data ? *)
- FOR i:= 1 TO len DO
- chksum := chksum + data[i]; (* loop for data *)
- chksum := CheckFunction(chksum); (* calculate checksum *)
- data[len+1] := MakeChar(chksum); (* make printable & output *)
- data[len+2] := SendEOL; (* EOL *)
- data[len+3] := ENDSTR;
- END;
-
- NumSendPacks := NumSendPacks+1;
- IF Debug
- THEN DebugPacket('Sending: ',ThisPacket);
- PutOut(ThisPacket);
-
- IF (RunType = Transmit) THEN
- BEGIN
- ChInPack := ChInPack + NumPad + len + 6;
- temp := LastPacket;
- LastPacket := ThisPacket;
- ThisPacket := temp;
- END;
- END
-
- END;
-
- PROCEDURE SendACK((* Using *) n:Integer); (* send ACK packet *)
- BEGIN
- WITH Buf[ThisPacket] DO
- BEGIN
- count := 0;
- seq := n;
- ptype := TYPEY;
- END;
- SendPacket;
- NumACK := NumACK+1;
- END;
-
- PROCEDURE SendNAK((* Using *) n:Integer); (* send NAK packet *)
- BEGIN
- WITH Buf[ThisPacket] DO
- BEGIN
- count := 0;
- seq := n;
- ptype := TYPEN;
- END;
- SendPacket;
- NumNAK := NumNAK+1;
- END;
-
-
-
- PROCEDURE GetData((* Returning *) VAR newstate:KermitStates);
- (* get data from file into ThisPacket *)
- VAR
- (* and return next state - data & EOF *)
- x,c : CharBytes;
- i: Integer;
- BEGIN
- IF (NumTry = 1) THEN
- BEGIN
- i := 1;
- x := ENDSTR;
- WITH Buf[ThisPacket] DO
- BEGIN
- WHILE (i< SizeSend - 8 ) AND (x <> ENDFILE)
- (* leave room for quote & NEWLINE *)
- DO
- BEGIN
- x := getcf(c,DiskFile);
- IF (x <> ENDFILE) THEN
- IF IsControl(x) OR (x = SendQuote) THEN
- BEGIN (* control char -- quote *)
- IF (x = LF) THEN (* use proper EOL *)
- BEGIN
- data[i] := SendQuote;
- i := i+1;
- data[i] := Ctl(CR);
- i := i+1;
- (* LF will sent below *)
- END;
- data[i] := SendQuote;
- i := i+1;
- IF (x <> SendQuote) THEN data[i] := Ctl(x)
- ELSE data[i] := SendQuote;
- END
- ELSE (* regular char *)
- data[i] := x;
-
- IF (x <> ENDFILE) THEN
- BEGIN
- i := i+1; (* increase count for next char *)
- ChInFile := ChInFile + 1 ;
- END;
- END;
-
- data[i] := ENDSTR; (* to terminate string *)
-
- count := i -1; (* length *)
- seq := n;
- ptype := TYPED;
-
- IF (x = ENDFILE) THEN
- BEGIN
- newstate := EOFile;
- Sclose(DiskFile);
- DiskFile := StdIOError;
- END
- ELSE
- newstate := FileData;
- SaveState := newstate; (* save state *)
- END
- END
- ELSE
- newstate := SaveState; (* get old state *)
- END;
-
- FUNCTION GetNextFile: (* Returning *) Boolean;
- (* get next file to send in ThisPacket *)
- (* returns true if no more *)
- (* ---- -- -pt*)
- VAR
- result: Boolean;
- BEGIN
- result := True;
- IF (NumTry = 1) THEN
- WITH Buf[ThisPacket] DO
- BEGIN
- IF GetArgument(data) THEN
- BEGIN (* open file *)
- IF Exists(data) THEN
- BEGIN
- (* Initialise counter for each file to be sent *)
- DataSendCount := 0 ;
-
- IF EightBitFile THEN (* [pgt001] *)
- DiskFile := Sopen(data,StdIO8Read)
- ELSE
- DiskFile := Sopen(data,StdIORead);
-
- count := ilength(data);
- ChInFile := ChInFile + count ;
- seq := n;
- ptype := TYPEF;
- Write('[Sending ');
- PutStr(data,stdout);
- Writeln(']') ;
- IF (DiskFile <= StdIOError) THEN
- ErrorMsg('?Can''t open file');
- result := False;
- END
- ELSE (* file does not exist *)
- BEGIN
- ErrorMsg('?Can''t find file: ') ;
- ErrorStr( data ) ;
- result := True (* I.e. fail: state -> abort *)
- END
- END;
- END
- ELSE
- result := False; (* for saved packet *)
- GetNextFile := result;
- END;
-
- PROCEDURE SendFile; (* send file name packet *)
- BEGIN
- Verbose( 'Sending ');
- IF (NumTry > MaxTry) THEN
- BEGIN
- ErrorMsg ('Send file - Too Many');
- State := Abort; (* too many tries, abort *)
- END
- ELSE
- BEGIN
- NumTry := NumTry+1;
- IF GetNextFile THEN
- BEGIN
- State := Break;
- NumTry := 0;
- END
- ELSE
- BEGIN
- IF Verbosity THEN
- IF (NumTry = 1)
- THEN ErrorStr(Buf[ThisPacket].data)
- ELSE ErrorStr(Buf[LastPacket].data);
- SendPacket; (* send this packet *)
- IF ReceiveACK THEN
- BEGIN
- State := FileData;
- NumTry := 0;
- n := (n+1) MOD 64;
- END
- END;
- END;
- END;
-
- PROCEDURE SendData; (* send file data packets *)
- VAR
- newstate: KermitStates;
- BEGIN
- IF (Land(DataSendCount, #03) = 0) THEN
- WITH OpenList[DiskFile] DO
- StreamProgress( FileVar ) ;
- DataSendCount := DataSendCount + 1 ; (* next "SendData" *)
-
- IF (NumTry > MaxTry) THEN
- BEGIN
- State := Abort; (* too many tries, abort *)
- ErrorMsg ('Send data - Too many');
- END
- ELSE
- BEGIN
- NumTry := NumTry+1;
- GetData(newstate);
- SendPacket;
- IF ReceiveACK THEN
- BEGIN
- State := newstate;
- NumTry := 0;
- n := (n+1) MOD 64;
- END
- END;
- END;
-
- PROCEDURE SendEOF; (* send EOF packet *)
- BEGIN
- Verbose ('Sending EOF');
- IF (NumTry > MaxTry) THEN
- BEGIN
- State := Abort; (* too many tries, abort *)
- ErrorMsg('Send EOF - Too Many');
- END
- ELSE
- BEGIN
- NumTry := NumTry+1;
- IF (NumTry = 1) THEN
- BEGIN
- WITH Buf[ThisPacket] DO
- BEGIN
- ptype := TYPEZ;
- seq := n;
- count := 0;
- END
- END;
- SendPacket;
- IF ReceiveACK THEN
- BEGIN
- State := FileHeader;
- NumTry := 0;
- n := (n+1) MOD 64;
- END
- END;
- END;
-
- PROCEDURE SendBreak; (* send break packet *)
- BEGIN
- Verbose ('Sending break');
- IF (NumTry > MaxTry) THEN
- BEGIN
- State := Abort; (* too many tries, abort *)
- ErrorMsg('Send break -Too Many');
- END
- ELSE
- BEGIN
- NumTry := NumTry+1;
- (* make up packet *)
- IF (NumTry = 1) THEN
- BEGIN
- WITH Buf[ThisPacket] DO
- BEGIN
- ptype := TYPEB;
- seq := n;
- count := 0;
- END
- END;
- SendPacket; (* send this packet *)
- IF ReceiveACK THEN
- BEGIN
- State := Complete;
- END
- END;
- END;
-
- PROCEDURE SendInit; (* send init packet *)
- BEGIN
- Verbose ('Sending Init');
- IF (NumTry > MaxTry) THEN
- BEGIN
- State := Abort; (* too many tries, abort *)
- ErrorMsg('Cannot Initialize');
- END
- ELSE
- BEGIN
- NumTry := NumTry+1;
- IF (NumTry = 1) THEN
- BEGIN
- WITH Buf[ThisPacket] DO
- BEGIN
- EnCodeParm(data);
- count := NUMPARAM;
- seq := n;
- ptype := TYPES;
- END
- END;
-
- SendPacket; (* send this packet *)
- IF ReceiveACK THEN
- BEGIN
- WITH Buf[CurrentPacket] DO
- BEGIN
- SizeSend := UnChar(data[1]);
- TheirTimeOut := UnChar(data[2]);
- NumPad := UnChar(data[3]);
- PadChar := Ctl(data[4]);
- SendEOL := CR; (* default to CR *)
- IF (ilength(data) >= 5) THEN
- IF (data[5] <> 0) THEN SendEOL := UnChar(data[5]);
- SendQuote := SHARP; (* default # *)
- IF (ilength(data) >= 6) THEN
- IF (data[6] <> 0) THEN SendQuote := data[6];
- END;
-
- State := FileHeader;
- NumTry := 0;
- n := (n+1) MOD 64;
- END;
- END;
- END;
-
-
- PROCEDURE SendSwitch;
- (* Send-switch is the state table switcher for sending files.
- * It loops until either it is finished or a fault is encountered.
- * Routines called by sendswitch are responsible for changing the state.
- *)
-
- HANDLER GotErrorPacket(VAR msg: istring) ;
- (* We got an error packet when trying to receive another packet. *)
- (* (possibly an ACK). Write the packet data and exit SEND command *)
- BEGIN
- Inverse( TRUE ) ;
- Writeln ;
- Writeln('?SEND received an error packet from the other Host') ;
- putstr(msg, STDOUT) ;
- Writeln ;
- Inverse( FALSE ) ;
- SClose( DiskFile ) ; (* close the disk file if its open *)
- State := Abort ;
- EXIT( SendSwitch )
- END ;
-
-
- BEGIN
- LoadCurs ; (* Load the progress cursors *)
- State := Init; (* send initiate is the start state *)
- NumTry := 0; (* say no tries yet *)
- IF (Delay > 0) THEN Sleep(Delay);
- REPEAT
- CASE State OF
- FileData: SendData; (* data-send state *)
- FileHeader: SendFile; (* send file name *)
- EOFile: SendEOF; (* send end-of-file *)
- Init: SendInit; (* send initialize *)
- Break: SendBreak; (* send break *)
- Complete: (* nothing *);
- Abort: (* nothing *);
- END (* case *);
- UNTIL ( (State = Abort) OR (State=Complete) );
-
- QuitProgress ; (* Remove progress cursors *)
-
- END.
-
- (* <<<KermitUtils>>> *)
- MODULE KermitUtils;
-
- EXPORTS
-
- IMPORTS KermitGlobals FROM KermitGlobals ;
-
-
- PROCEDURE StartTimer;
- PROCEDURE CheckTimer ;
- PROCEDURE StopTimer;
- PROCEDURE XmtChar(ch:Char); (* Perq version -pt*)
- FUNCTION GetIn :CharBytes; (* get character *)
- FUNCTION UnChar(c:CharBytes): CharBytes;
- FUNCTION MakeChar(c:CharBytes): CharBytes;
- FUNCTION IsControl(c:CharBytes): Boolean;
- FUNCTION IsPrintable(c:CharBytes): Boolean;
- FUNCTION Ctl(c:CharBytes): CharBytes;
- FUNCTION IsValidPType(c:CharBytes): Boolean;
- FUNCTION CheckFunction(c:Integer): CharBytes;
- FUNCTION ilength (VAR s : istring) : Integer;
- FUNCTION GetArgument(VAR arg: istring): Boolean ;
- PROCEDURE EnCodeParm(VAR data:istring); (* encode parameters *)
- PROCEDURE DeCodeParm(VAR data:istring); (* decode parameters *)
- PROCEDURE Inverse( turn_on: Boolean ) ;
-
-
-
-
- PRIVATE
-
-
-
- IMPORTS IOErrors FROM IOErrors ;
- IMPORTS IO_Unit FROM IO_Unit ;
- IMPORTS IO_Others FROM IO_Others ;
- IMPORTS CmdParse FROM CmdParse ;
- IMPORTS Screen FROM Screen ;
-
- {$RANGE-}
-
- FUNCTION UnChar(c:CharBytes): CharBytes;
- (* reverse of makechar *)
- BEGIN
- UnChar := c - BLANK
- END;
-
-
- FUNCTION MakeChar(c:CharBytes): CharBytes;
- (* convert integer to printable *)
- BEGIN
- MakeChar := c + BLANK
- END;
-
- FUNCTION IsControl(c:CharBytes): Boolean;
- (* true if control *)
- BEGIN
- (* Clear the 8th bit *)
- c := Land( c, #177 ) ;
- IsControl := (c = DEL) OR (c < BLANK)
- END;
-
- FUNCTION IsPrintable(c:CharBytes): Boolean;
- (* opposite of iscontrol *)
- BEGIN
- IsPrintable := NOT IsControl(c)
- END;
-
- FUNCTION Ctl(c:CharBytes): CharBytes;
- (* c XOR 100 *)
- BEGIN
- Ctl := LXor(c, #100)
- END;
-
- FUNCTION IsValidPType(c:CharBytes): Boolean;
- (* true if valid packet type *)
- BEGIN
- IsValidPType :=
- c IN [TYPEB, TYPED, TYPEE, TYPEF, TYPEN, TYPES, TYPET, TYPEY, TYPEZ]
- END;
-
- FUNCTION CheckFunction(c:Integer): CharBytes;
- (* calculate checksum *)
- VAR
- x: Integer;
- BEGIN
- (* CheckFunction := (c + ( c AND 300 ) /100 ) AND 77; *)
- x := Shift( Land(c, #300), -6) ;
- CheckFunction := Land(x+c, #077)
- END;
-
- PROCEDURE EnCodeParm((* Updating *) VAR data:istring); (* encode parameters *)
- VAR
- i: Integer;
- BEGIN
- FOR i:=1 TO NUMPARAM DO
- data[i] := BLANK;
- data[NUMPARAM+1] := ENDSTR;
- data[1] := MakeChar(SizeRecv); (* my biggest packet *)
- data[2] := MakeChar(MyTimeOut); (* when I want timeout*)
- data[3] := MakeChar(MyPad); (* how much padding *)
- data[4] := Ctl(MyPadChar); (* my padding character *)
- data[5] := MakeChar(myEOL); (* my EOL *)
- data[6] := MyQuote; (* my quote char *)
- END;
-
- PROCEDURE DeCodeParm(VAR data:istring); (* decode parameters *)
- BEGIN
- SizeSend := UnChar(data[1]);
- TheirTimeOut := UnChar(data[2]); (* when I should time out *)
- NumPad := UnChar(data[3]); (* padding characters to send *)
- PadChar := Ctl(data[4]); (* padding character *)
- SendEOL := UnChar(data[5]); (* EOL to send *)
- SendQuote := data[6]; (* quote to send *)
- END;
-
-
- { Copyright (C) 1981 by Bell Laboratories, Inc., and Whitesmiths Ltd. }
- { length -- compute length of string }
- FUNCTION ilength (VAR s : istring) : Integer;
- VAR
- n : Integer;
- BEGIN
- n := 1;
- WHILE (s[n] <> ENDSTR) DO
- n := n + 1;
- ilength := n - 1
- END;
-
-
-
- PROCEDURE StartTimer;
- (* Start the time count, in clock ticks. -pt*)
- BEGIN
- IOGetTime( OldTime ) ; (* Current clock value *)
- TimeLeft := TheirTimeOut * 60 (* in ticks *)
- END;
-
- PROCEDURE CheckTimer ;
- (* Decrement "TimeLeft" by time between last call and now -pt*)
- VAR now: Double ;
- BEGIN
- IF (TimeLeft > 0) THEN (* Still counting *)
- BEGIN
- IOGetTime( now ) ;
- TimeLeft := TimeLeft - now[0] + OldTime[0] ;
- OldTime := now
- END
- END ;
-
- PROCEDURE StopTimer;
- BEGIN
- TimeLeft := Maxint;
- END;
-
-
- (*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*)
-
-
- PROCEDURE XmtChar(ch:Char); (* Perq version -pt*)
- BEGIN
- WHILE IOCWrite(RS232Out, ch) <> IOEIOC DO (* nothing *) ;
- END;
-
-
- FUNCTION GetIn :CharBytes; (* get character *)
- (* Should return NULL (ENDSTR) if no characters, Perq version -pt*)
- VAR
- byte: CharBytes ;
- c :Char ;
- BEGIN
- IF (IOCRead(RS232In, c) = IOEIOC) THEN
- BEGIN
- byte := land( Ord(c), #377 ) (* [pgt001] *)
- END
- ELSE byte := ENDSTR ;
- GetIn := byte ;
- (* ChInPack := ChInPack + 1.0 (@ AddTo( x, 1) *)
- END;
-
-
- (*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*)
-
-
- (* Get the next argument from the command line -pt*)
- (* Return True if an argument is available - returned in "arg" too -pt*)
- FUNCTION GetArgument(VAR arg: istring): Boolean ;
- VAR
- return: Boolean ; (* Return value *)
- i, len: Integer ; (* index and argument length *)
- id: String ; (* Identifier/argument from the line *)
- BEGIN (*-GetArgument-*)
- dumCh := NextIDString( CmdLine, id, return ) ; (* Get an identifier *)
- IF (id = '') THEN return := False (* nothing *)
- ELSE
- BEGIN
- return := True ; (* Success *)
- len := Length( id ) ; (* get the string's length *)
- FOR i := 1 TO len DO (* put the string in "arg" *)
- arg[i] := Ord( id[i] ) ;
- arg[len+1] := ENDSTR (* finish it off *)
- END ;
- GetArgument := return
- END ; (*-GetArgument-*)
-
- PROCEDURE Inverse( turn_on: Boolean ) ;
- (* Change chrsor function for inverse video *)
- BEGIN (*-Inverse-*)
- IF turn_on THEN SChrFunc( RNot )
- ELSE SChrFunc( RRpl )
- END (*-Inverse-*).
-
- (* <<<Stdio.Pas>>> *)
- MODULE STDIO ;
- (* Standard text file I/O *)
- (* from Kernighan + Plauger *)
- (* 29-Nov-83 Allow eight bit file transfer [pgt001] *)
- (* This forces us to make the end of (data) string value -1 *)
- (* and end of file value -2 because byte values can be 0..255 *)
-
-
- EXPORTS
-
- IMPORTS KermitGlobals FROM KermitGlobals ;
-
- CONST
- { standard file descriptors. subscripts in open, etc. }
- STDIN = 1; { these are not to be changed }
- STDOUT = 2;
- STDERR = 3;
- lineout = 4;
- linein = 5;
- FirstUserFile = STDERR ; (* First index available for user's files -pt*)
-
- { other io-related stuff }
- StdIOError = 0; { status values for open files }
- StdIOAvail = 1;
- StdIORead = 2;
- StdIOWrite = 3;
- StdIO8Read = 4 ; (* [pgt001] *)
- StdIO8Write = 5 ; (* [pgt001] *)
- MAXOPEN = 15; { maximum number of open files }
-
- { universal manifest constants }
- ENDFILE = ENDSTR - 1; (* [pgt001] *)
-
- TYPE
- filedesc = StdIOError..MAXOPEN;
- ioblock = RECORD { to keep track of open files }
- filevar : Text;
- mode : StdIOError..StdIO8Write;
- END;
-
- VAR
- openlist : ARRAY [1..MAXOPEN] OF ioblock; { open files }
-
- PROCEDURE StdIOInit;
- PROCEDURE putch (c : CharBytes);
- PROCEDURE putcf (c : CharBytes; fd : filedesc);
- PROCEDURE putstr (VAR s : istring; f : filedesc);
- FUNCTION getch (VAR c : CharBytes) : CharBytes;
- FUNCTION getcf (VAR c: CharBytes; fd : filedesc) : CharBytes;
- FUNCTION getline (VAR s : istring; fd : filedesc;
- maxsize : Integer) : Boolean;
-
- FUNCTION Sopen (name : istring; mode : Integer) : filedesc;
- PROCEDURE Sclose (fd : filedesc);
- FUNCTION Exists(s:istring): Boolean;
-
- PRIVATE
-
-
- IMPORTS Perq_string FROM Perq_String ;
- IMPORTS Stream FROM Stream ;
- IMPORTS FileSystem FROM FileSystem ;
-
-
- { StdIOInit -- initialize open file list }
- PROCEDURE StdIOInit;
- VAR
- i : filedesc;
- BEGIN
- openlist[STDIN].mode := StdIORead;
- openlist[STDOUT].mode := StdIOWrite;
- { initialize rest of files }
- FOR i := FirstUserFile TO MAXOPEN DO
- openlist[i].mode := StdIOAvail;
-
- END;
-
-
- { getc (UCB) -- get one character from standard input }
- FUNCTION getch (VAR c : CharBytes) : CharBytes;
- VAR
- ch : Char;
- BEGIN
- IF Eof THEN c := ENDFILE
- ELSE
- IF Eoln THEN
- BEGIN
- Readln;
- c := LF
- END
- ELSE
- BEGIN
- Read(ch);
- c := Ord(ch)
- END;
- getch := c
- END;
-
- { Copyright (C) 1981 by Bell Laboratories, Inc., and Whitesmiths Ltd. }
- { getcf (UCB) -- get one character from file }
- FUNCTION getcf (VAR c: CharBytes; fd : filedesc) : CharBytes;
- VAR
- ch : Char;
- BEGIN
- WITH openlist[fd] DO (* [pgt001] *)
- IF (fd = STDIN) THEN getcf := getch(c)
- ELSE
- IF Eof(filevar) THEN c := ENDFILE
- ELSE
- IF (mode = StdIO8Read) THEN (* [pgt001] *)
- BEGIN
- c := Ord( filevar^ ) ;
- Get( filevar )
- END (* [pgt001] *)
- ELSE
- IF Eoln(filevar) THEN
- BEGIN
- Readln(filevar);
- c := LF
- END
- ELSE
- BEGIN
- Read(filevar, ch);
- c := Ord(ch)
- END;
- getcf := c
- END;
-
- { Copyright (C) 1981 by Bell Laboratories, Inc., and Whitesmiths Ltd. }
- { getline (UCB) -- get a line from file }
- FUNCTION getline (VAR s : istring; fd : filedesc;
- maxsize : Integer) : Boolean;
- VAR
- i : Integer;
- c : CharBytes;
- BEGIN
- {$RANGE-}
- i := 1;
- REPEAT
- s[i] := getcf(c, fd);
- i := i + 1
- UNTIL (c = ENDFILE) OR (c = LF) OR (i >= maxsize);
- IF (c = ENDFILE) THEN i := i - 1 ; { went one too far }
- s[i] := ENDSTR;
- getline := (c <> ENDFILE)
- {$RANGE+}
- END;
-
- { Copyright (C) 1981 by Bell Laboratories, Inc., and Whitesmiths Ltd. }
- { putch (UCB) -- put one character on standard output }
- PROCEDURE putch (c : CharBytes);
- BEGIN
- IF (c = LF) THEN Writeln
- ELSE Write(Chr(c))
- END;
-
- { Copyright (C) 1981 by Bell Laboratories, Inc., and Whitesmiths Ltd. }
- { putcf (UCB) -- put a single character on file fd }
- PROCEDURE putcf (c : CharBytes; fd : filedesc);
- CONST
- NUL = 0 ;
- BEGIN
- WITH openlist[fd] DO
- IF (fd = STDOUT) THEN putch(c)
- ELSE
- IF (mode = StdIO8Write) THEN (* [pgt001] *)
- BEGIN
- filevar^ := Chr(c) ;
- Put( filevar )
- END
- ELSE
- BEGIN (* Normal text file [pgt001]*)
- c := Land(c, #177) ;
- IF (c = LF) THEN Writeln(filevar)
- ELSE
- IF (c = CR) OR (c = NUL) THEN (* ignore *)
- ELSE
- Write(filevar, Chr( c ))
- END ;
- END;
-
- { Copyright (C) 1981 by Bell Laboratories, Inc., and Whitesmiths Ltd. }
- { putstr (UCB) -- put out string on file }
- PROCEDURE putstr (VAR s : istring; f : filedesc);
- VAR
- i : Integer;
- BEGIN
- {$RANGE-}
- i := 1;
- WHILE (s[i] <> ENDSTR) DO
- BEGIN
- putcf(s[i], f);
- i := i + 1
- END
- {$RANGE+}
- END;
-
-
- { MakeString -- Convert an istring into a Perq String variable -pt }
- PROCEDURE MakeString(src: istring; VAR dest: String) ;
- VAR
- i: Integer ;
- BEGIN (*-MakeString-*)
- i := 1 ;
- {$RANGE- Checks off because Length(dest) undefined at the moment -pt}
- WHILE (src[i] <> ENDSTR) AND (src[i] <> LF) DO
- BEGIN
- dest[i] := Chr(src[i]) ;
- i := i + 1
- END ;
- {$RANGE+ Checks back on -pt}
- Adjust(dest, i-1) (* Set the dynamic length -pt*)
- END ; (*-MakeString-*)
-
- { open -- open a file for reading or writing. Perq version -pt}
- FUNCTION Sopen (name : istring; mode : Integer) : filedesc;
- VAR
- i : Integer;
- filename : String ;
- found : Boolean;
-
- (* Reset and Rewrite error handlers. Both set "sopen" to IOERROR -pt*)
- (* This means we set inital value of "sopen" before reset/rewrite -pt*)
- HANDLER ResetError(filnam: PathName) ;
- BEGIN
- sopen := StdIOError
- END ;
- HANDLER RewriteError(filnam: PathName) ;
- BEGIN
- sopen := StdIOError
- END ;
-
- BEGIN
- MakeString(name, filename) ; (* Convert to Perq string -pt*)
- { find a free slot in openlist }
- Sopen := StdIOError;
- found := False;
- i := 1;
- WHILE (i <= MAXOPEN) AND (NOT found) DO
- BEGIN
- IF (openlist[i].mode = StdIOAvail) THEN
- BEGIN
- openlist[i].mode := mode ;
- Sopen := i; (* Here so file handlers can reset value -pt*)
- IF (mode = StdIORead) OR (mode = StdIO8Read) THEN
- Reset(openlist[i].filevar, filename) (* [pgt001] *)
- ELSE
- Rewrite(openlist[i].filevar, filename);
- found := True
- END;
- i := i + 1
- END
- END;
-
- PROCEDURE Sclose (fd : filedesc);
- BEGIN
- IF (fd >= FirstUserFile) AND (fd <= MAXOPEN) THEN
- BEGIN
- openlist[fd].mode := StdIOAvail;
- close(openlist[fd].filevar);
- END
- END;
-
-
- FUNCTION Exists(s:istring): Boolean;
- (* returns true if file exists. Perq version -pt*)
- VAR
- name: String ;
- file_id, blocks, bits: Integer ;
- BEGIN (*-Exists-*)
- (* Be quick and use a look-up; better than open/close sequence -pt*)
- MakeString(s, name) ; (* Get the file name as a Perq string *)
- file_id := FSLookUp(name, blocks, bits) ; (* Do the look-up *)
- Exists := (file_id <> 0) (* Zero means it does not exist *)
- END. (*-Exists-*)
-